#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件   :control_main.py
@说明   :
@时间   :2024/04/28 12:40:03
@作者   :TaoHong
@版本   :v1.0
'''



import traci
import sumolib

import os
import multiprocessing

import xml.etree.ElementTree as ET


import control_Accident as ACC
import control_reset_flow as RF



def run_default(sumo_cmd, sumo_cfg, num_scene, PORT=7911):
    """
    run_default
    start 仿真
    """
    #! 场景的输入
    str_num_scene = str(num_scene)
    getcmd = [sumo_cmd
            ,'-c', sumo_cfg
            ,'--start', "True"
            ,'--quit-on-end', "True"
            ,"--delay", "0"
            ,"--no-warnings", "true"
            ,"--no-step-log", "True"
            # ,"--fcd-output", "output/fcd_accident_after_and_control_after.xml" #! 生成FCD文件
            ,"--num-clients", str_num_scene
            ,"--time-to-teleport", "50"
            ,"--time-to-teleport.remove", "True"
            ]
    
    # print(getcmd)
    
    traci.start(getcmd, port=PORT, label="main")
    traci.setOrder(0)
    
    step = 0
    while traci.simulation.getMinExpectedNumber() > 0:
        traci.simulationStep()
        step += 1

        if step==1000: # 停止时间
            break

    traci.close()



class startSumo:

    def __init__(self
                 , gui_tag
                 , scene_accident_tag 
                 , control_vsl_tag
                 ):
        """
        gui_tag             # 是否开启 GUI
        control_vsl_tag     # 是否开启 可变限速管控
            实际control_vsl_tag =  True 时的 before信息，每个周期都是实施管控后的 交通流信息
            control_vsl_tag =  False 时， run_no_variable_speed_limit()
            发挥作用，用于 更新 管控前的数据 before

        scene_accident_tag  # 是否开启 事故
        """

        self.gui_tag = gui_tag          # 是否开启 GUI
        self.control_vsl_tag = control_vsl_tag  # 是否开启 VSL管控
        self.scene_accident_tag = scene_accident_tag      # 是否开启 事故
  

        #! 新增场景
        self.scene_flag_list = [] # 开启 哪些场景 
        
        if self.scene_accident_tag: # 事故
            self.scene_flag_list.append('scene_accident_tag')

        if self.control_vsl_tag:    # VSL管控
            self.scene_flag_list.append('control_vsl_tag') 
        # else:
        #     self.scene_flag_list.append('no_control_vsl_tag') # 开启与否，都要把这个场景的数量加上
        
        


    def start_sumo(self, acc_scene_dict, control_vsl_dict):
        """
        自动打开运行sumo-gui
        """
        # 通用启动项目
        sumo_cmd = sumolib.checkBinary('sumo')
        if self.gui_tag: # GUI-界面打开sumo-gui运行
            sumo_cmd = sumolib.checkBinary('sumo-gui')    
        
        self.sumo_cfg = control_vsl_dict['sumo_cfg']
        
        #! 开始仿真
        print('开始仿真!')
        
        num_scene = len(self.scene_flag_list)+1 # 
        
        print("\n开启场景数量: {}, (包括启动场景): ".format(num_scene))
        print(self.scene_flag_list)
        
        if num_scene > 1:
            self.process_list = []
            #* 默认 开启场景
            service = multiprocessing.Process(name='run_default',target=run_default
                                              , args=(sumo_cmd, self.sumo_cfg, num_scene))
            self.process_list.append(service) # s0
            
            #* 添加新功能处:
            if self.scene_accident_tag:
                acc = ACC.Accident()
                add_s1= multiprocessing.Process(name='run_accident',target=acc.run_accident
                                                , args=(sumo_cmd, acc_scene_dict))
                self.process_list.append(add_s1)


            # if self.control_vsl_tag:
            #     VSL = GVSL.variableSpeedLimit()
            #     add_s2 = multiprocessing.Process(name='control_vsl_tag',target=VSL.run_variable_speed_limit
            #                                      , args=(sumo_cmd, control_vsl_dict, acc_scene_dict))
            #     self.process_list.append(add_s2)
            # else:
            #     VSL = GVSL.variableSpeedLimit()
            #     add_s3 = multiprocessing.Process(name='no_control_vsl_tag',target=VSL.run_no_variable_speed_limit
            #                                      , args=(sumo_cmd, control_vsl_dict, acc_scene_dict))
            #     self.process_list.append(add_s3)

            #* 并行
            for p in self.process_list:
                p.start()
            for j in self.process_list:
                j.join()


        else:
            print("===================")
            #* 默认 开启场景
            service = multiprocessing.Process(name='run_default',target=run_default
                                              , args=(sumo_cmd, self.sumo_cfg, num_scene))
            service.start()
            service.join()


if __name__=='__main__':

    _my_cwd_ = os.path.split(os.path.realpath(__file__))[0]
    os.chdir(_my_cwd_)


    #! 修改流量  ************************ 开始 ****************************
    
    #! 修改流量 的输入>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Begin

    reset_flow_tag = True #! 是否开启流量修改
    # reset_flow_tag = False #!

    root = ET.Element("routes")

    truck_rate_ls = [  0.3, 0.2, 0.2
                     , 0.1, 0.2, 0.1
                     , 0.1, 0.1, 0.3] # 各个Origin的大车占比
    flow_state_dict = {}
    
    # 正常车辆
    flow_file = "Flow-vType.xlsx"
    flow_state_dict['flow_file'] = flow_file
    flow_state_dict['net_file'] = 'osm_road.net.xml'      # 路网
    flow_state_dict['rou_file'] = 'osm.rou.xml'
    
    flow_state_dict['truck_rate_ls'] = truck_rate_ls
    
    # 事故车
    flow_state_dict['emerg_id'] = 'accident_veh1'

    #! 修改流量 的输入<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<End
    
    if reset_flow_tag: # 有修改才变流量
        print(f" 修改流量文件：{flow_file};\n 修改CAV比例为{truck_rate_ls}")
        RESET_FLOW = RF.resetFlow()
        RESET_FLOW.run_reset_flow(root, flow_state_dict)
    else:
        print('不修改流量！')
    

    #! 自动仿真  ************************ 场景开启 ****************************
    #* 是否开启 GUI
    gui_tag = True
    # gui_tag = False #? 不用 GUI 界面 不看效果的时候，就用这个
    
    #* 是否开启 事故
    scene_accident_tag = True

    #* 是否开启 可变限速 管控
    control_vsl_tag = True
    control_vsl_tag = False


    #! 自动仿真 ***************************************************************

    #! VSL 管控的输入>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Begin
    # 停止仿真的时间
    y = 10  #* 管控的周期数量
    # y = 3  #* 管控的周期数量 # 分析前三个周期的时候用

    end_control_step = 180 + 60*y   # 结束管控
    start_control_step = 180        # 开始管控

    control_vsl_dict = {}
    control_vsl_dict['sumo_cfg'] = "osm.sumocfg"
    control_vsl_dict['CAV_rate'] = 0.3
    control_vsl_dict['end_control_step'] = end_control_step
    control_vsl_dict['start_control_step'] = start_control_step
    #! VSL 管控的输入<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<End


    #! accident 场景的输入>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>begin
    acc_scene_dict = {}
    acc_scene_dict['emerg_id'] = 'accident_veh1'
    acc_scene_dict['emerg_edge'] = '579777264#0.1094' # 自定义
    
    
    start_emerg_step = 150  # 开始事故 #! 
    end_emerg_step = 560    # 结束事故 #! 
    brake_len = 400                   #! 刹车的距离

    acc_scene_dict['start_emerg_step'] = start_emerg_step
    acc_scene_dict['end_emerg_step'] = end_emerg_step
    acc_scene_dict['brake_len'] = brake_len
    
    #! accident 场景的输入<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<End


    #! 开始仿真    
    MAIN_SUMO = startSumo(gui_tag
                          , scene_accident_tag
                          , control_vsl_tag
                          )
    
    MAIN_SUMO.start_sumo(acc_scene_dict
                         , control_vsl_dict
                         )
